#include <Arduino.h>

#include <String.h>
#include "nfc.h"
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>

#define DEBUG 0

const int chipSelect = 4; //Пин карты
const int id_lench = 8; //Длинна метки NFC
const int max_files = 10;//Максимальное колличество юзеров
const int max_commandline = 20; //максимальный размер комманды GET
const byte dorPin = 8;

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.

uint8_t test_id[id_lench] = { 0xFF, 0x12, 0x13, 0x14, 0x15, 0x16, 0x00, 0xFF };

/** define a nfc class */
NFC_Module nfc;

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,1,177);
EthernetServer server(80);

//Sd2Card card;
//SdVolume volume;
//SdFile root;


class id_db {

protected:
//	String config_file;

//	char filename[];
	Sd2Card card;
	SdVolume volume;
//	File root;
	SdFile root;


public:
	int name_count;
	String name_files[max_files];


	id_db() {
//		if (!SD.begin(chipSelect)) {
//#ifdef DEBUG
//			Serial.println("Card failed, or not present");
//#endif
//			// don't do anything more:
//			return;
//		}
//
		name_count = 0;
	}

	void begin(){

		if (!card.init(SPI_QUARTER_SPEED, chipSelect)) {
#ifdef DEBUG
		    Serial.println("Initialization failed");
#endif
		     return;
		  }
		 if (!volume.init(&card)) {
#ifdef DEBUG
		    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
#endif
		    return;
		  }
		 root.openRoot(&volume);
#ifdef DEBUG
		Serial.println("card initialized, OK.");
#endif

	}

	String ListFiles() {
	  // This code is just copied from SdFile.cpp in the SDFat library
	  // and tweaked to print to the client output in html!
	  dir_t p;
//	  String out[max_files];
	  root.rewind();
	  name_count = 0;

	  while (root.readDir(p) > 0) {
//		  файлов не больше 10ти
		if (name_count > max_files) {
#ifdef DEBUG
		    Serial.println("To many files!!!");
#endif
			break;
		}
	    // done if past last used entry
	    if (p.name[0] == DIR_NAME_FREE) break;

	    // skip deleted entry and entries for . and  ..
	    if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.') continue;

	    // only list files
	    if (!DIR_IS_FILE(&p)) continue;
	    int i = 0;
	    name_files[name_count]= "";
	    while (i <= 10 ) {
	      if (p.name[i] == ' ') {
	    	  i++;
	    	  continue;
	      }
	      name_files[name_count]+= (char)p.name[i];
	      i++;
	    }
#ifdef DEBUG
	    Serial.println("print array");
	    Serial.println(name_files[name_count]);
#endif
	    name_count++;
	  }
	  return * name_files;
	}

//	void begin(){
//
////		root.rewindDirectory();
//	//		File entry;
//	//	while (true) {
//		File file_root = SD.open("/");
//		printDirectory(file_root,0);
//		for (name_count = 0; name_count <= max_files; name_count++) {
//			File entry = file_root.openNextFile();
//			if (!entry) {
//				file_root.rewindDirectory();
//				break;
//			}
//			if (entry.isDirectory()) {
//				continue; //директорию пропускаем
//			}
//	#ifdef DEBUG
//			Serial.println(entry.name());
//			Serial.println(name_count);
//	#endif
//			name_files[name_count] = entry.name();
//			entry.close();
//		}
//	#ifdef DEBUG
//		Serial.print("No more files, count: ");
//		Serial.println(name_count);
//	#endif
//
////		printDirectory(root, 0);
//	}

//	void printDirectory() {
//		File dir;
//		dir = SD.open("/");
//		dir.rewindDirectory();
//	   while(true) {
//
//	     File entry =  dir.openNextFile();
//	     if (! entry) {
//	       // no more files
//	       Serial.println("**nomorefiles**");
//	       break;
//	     }
////	     for (uint8_t i=0; i<numTabs; i++) {
////	       Serial.print('\t');
////	     }
//	     Serial.print(entry.name());
//	     if (entry.isDirectory()) {
//	       Serial.println("/");
////	       printDirectory(entry, numTabs+1);
//	     } else {
//	       // files have sizes, directories do not
//	       Serial.print("\t\t");
//	       Serial.println(entry.size(), DEC);
//	     }
//	     entry.close();
//	   }
//	}

//	void printDirectory(File dir, int numTabs) {
//		/*
//		 * Rewinding the directory each call
//		 */
//		dir.rewindDirectory();
//		while (true) {
//			File entry = dir.openNextFile();
//			if (!entry) {
//				// no more files
//				Serial.println("**nomorefiles**");
//				break;
//			}
//			for (uint8_t i = 0; i < numTabs; i++) {
//				Serial.print('\t');
//			}
//			Serial.print(entry.name());
//			if (entry.isDirectory()) {
//				Serial.println("/");
//				printDirectory(entry, numTabs + 1);
//			} else {
//				// files have sizes, directories do not
//				Serial.print("\t\t");
//				Serial.println(entry.size(), DEC);
//			}
//			/*
//			 * The following line was added to fix the maximum open file count bug.
//			 */
//			entry.close();
//
//		}
//	}

//	void make_db( String config_file){
//		  filename[config_file.length()+1];
//		  config_file.toCharArray(filename, sizeof(filename));
//		  if (!SD.exists(filename)) {
//			  Serial.println("config not exist, nobody not may enter");
//		#ifdef DEBUG
//		  }else{
//
//		    Serial.println("config exists.");
//		  }
//		#endif
// 	}

	void write(char *filename, String s) {
//
		del(filename);
		File file = SD.open(filename, FILE_WRITE);
//			file.write(id, id_lench);
		file.println(s);
#ifdef DEBUG
		Serial.print("In file write: ");
		Serial.println(s);
#endif
		file.flush();
		file.close();
	}

	String read(char *filename) {
		String s;
		char c;
		File file = SD.open(filename, FILE_READ);
		for (int i = 0; i < id_lench*2; i++) {
			if (file.available()) {
				c = file.read();
				s += c;
			} else {
#ifdef DEBUG
				Serial.println("NOT expected end of file: ");
#endif
				break;
			}
		}
#ifdef DEBUG
		Serial.print("Read from file all ");
		Serial.println(s);
#endif
		file.close();
		return s;
	}

	String read(String  filename) {
		char c;
		char name[8];
		String s;
		filename.toCharArray(name, 8);
		File file = SD.open(name, FILE_READ);
		for (int i = 0; i < id_lench*2; i++) {
			if (file.available()) {
				c = file.read();
				s += c;
			} else {
#ifdef DEBUG
				Serial.println("NOT expected end of file: ");
#endif
				break;
			}
		}
#ifdef DEBUG
		Serial.print("Read from file all ");
		Serial.println(s);
#endif
		file.close();
		return s;
	}

	String read(File file) {
		String s;
		char c;
		for (int i = 0; i < id_lench*2; i++) {
			if (file.available()) {
				c = file.read();
				s += c;
			} else {
#ifdef DEBUG
				Serial.println("NOT expected end of file: ");
#endif
				break;
			}
		}
#ifdef DEBUG
		Serial.print("Read from file: ");
		Serial.println(s);
#endif
		file.close();
		return s;
	}

//	boolean search(String id) {
////		root.rewindDirectory();
////		File entry;
//		char * name;
////		printDirectory(root, 0);
//		for (int i = 0; i <= name_count; i++) {
////	char c[8];
////	name_files[i].toCharArray(c, 8);
//			if (id == read(name_files[i])) {
//#ifdef DEBUG
//				Serial.print("Entry found in file name: ");
//				Serial.println(name);
//#endif
//				return 1;
////				break;
//			}
//		}
//#ifdef DEBUG
//		Serial.println("No more files.");
//#endif
//		return 0;
//	}
//
	void del(char *filename) {

		if (SD.exists(filename)) {
			SD.remove(filename);
#ifdef DEBUG
			Serial.println("file exist, delete OK");
#endif
		}
	}
};

String byte_to_string(uint8_t *id) {
	String s;
	char c;
	u8 hextab[17] = "0123456789ABCDEF";
	for (u32 i = 0; i < id_lench; i++) {
		c = hextab[(id[i] >> 4) & 0x0F];
		s += c;
		c = hextab[id[i] & 0x0F];
		s += c;
	}
#ifdef DEBUG
	Serial.println("Convert to: ");
	Serial.println(s);
	Serial.println("Convert nfc.puthex: ");
	nfc.puthex(id, id_lench);
#endif
	return s;
}

// the setup routine runs once when you press reset:

id_db DB;

void setup() {

	Serial.begin(57600);
	nfc.begin();
	TWBR = 152;  //скорость 50кГц
//  TWSR |= _BV (TWPS0);

	DB.begin();
	DB.ListFiles();
//	String s;

//	String s = DB.ListFiles();
//for (int i=0 ; i <= DB.name_count ; i++){
//	Serial.println(s[i]);
//}
//for (int i=0 ; i <= DB.name_count ; i++){
//	Serial.println(DB.name_files[i]);
//}
	Ethernet.begin(mac, ip);
	server.begin();

	pinMode(dorPin, OUTPUT);

//  uint32_t versiondata = nfc.get_version();
//  if (! versiondata) {
//	delay(500);
//    Serial.println("Didn't find PN53x board.");
//    setup(); // try once more почему так не логичнее ли while???
//    return;//while (1); // halt
//  }

	// Got ok data, print it out!
//  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
//  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
//  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);

	/** Set normal mode, and disable SAM */
//  nfc.SAMConfiguration();
//  PgmPrint("Free RAM: ");
//	  Serial.println(FreeRam());

}

void openDor() {
	digitalWrite(dorPin, HIGH);
	delay(100);
	digitalWrite(dorPin, LOW);
	delay(300);
}

// the loop routine runs over and over again forever:
void loop() {

//	DB.ListFiles();
//	id_db DB;
//  u8 buf[32],sta; //не знаю что это
//
//  /** Polling the mifar card, buf[0] is the length of the UID */
//  sta = nfc.InListPassiveTarget(buf);
//  digitalWrite(dorPin, LOW);
//
//  /** check state and UID length */
//  if(sta)
//  {
    //digitalWrite(led13, LOW); // ЗАЧЕМ???

    /** he card may be Mifare Classic card, try to read the block */
    /** this sketch was written by toc at arduino ru */
    // � ������� �������� ������� ����� ����� ������ �����
//	Serial.print("UUID length:");
//	Serial.print(sizeof(test_id));
//	Serial.println();
//	Serial.print("UUID:");
//	nfc.puthex(test_id, sizeof(test_id));
//	Serial.println();
//
//	delay(5000);
//DB.begin();

  //  String s = DB.list_files();

//for ( int i=0; i<4 ; i++){
//Serial.println(DB.count_files());
//Serial.println(s[2]);
//}

	  EthernetClient client = server.available();
	  int index = 0;
	  char raw_cmd[max_commandline];
	  String command;
	  int end_index =  max_commandline;
	  int del_index = -1;
	  if (client) {
	    // an http request ends with a blank line
	    boolean currentLineIsBlank = true;
	    while (client.connected()) {
	      if (client.available()) {
	        char c = client.read();

	        Serial.println(c);
	        Serial.println(command);
	        if (c != '\n') {
	        	command += c;
//	            if (index < max_commandline) raw_cmd[index] = c;
	   	  	      index++;
//	   	  		if (index >= max_commandline) index = max_commandline - 1;
	   	  	      continue;
	        }

	        if (c == '\r'){
	        	continue;
	        }

//	        command = raw_cmd;
	        end_index = command.lastIndexOf(' ');
	        del_index = command.lastIndexOf("?");
//#ifdef DEBUG
		      Serial.println("commandline- :");
		      Serial.println(command);
		      Serial.println(" index: ");
		      Serial.println(del_index);
		      Serial.println(command.substring(0,14));
//#endif
	        // if you've gotten to the end of the line (received a newline
	        // character) and the line is blank, the http request has ended,
	        // so you can send a reply
		      if ( command.substring(5,6) == " " ) {
	          // send a standard http response header
	          client.println("HTTP/1.1 200 OK");
	          client.println("Content-Type: text/html");
	          client.println();

	          // output the value of each analog input pin
	          Serial.println("Connect ....");
	            client.println("Available users: ");

//	        for (int i=0 ; i <= DB.name_count ; i++){
//	        	char c[DB.name_files[i].length()];
//	        	DB.name_files[i].toCharArray(c,DB.name_files[i].length()+1);
//	        	client.print("<li>");
//	        	client.print(c);
//	        	client.println("    del </li>");
//	        	Serial.println(DB.name_files[i]);
//	        }
	        client.println();
	        Serial.println("END ....");
//	            for (int i = 0; i<=DB.name_count; i++){
//	            	 client.println(DB.name_files[i]);
//	            	 Serial.println(DB.name_files[i]);
//	            }

//	             client.print(DB.list_files());
	        break;
	        }

		      if ( command.substring(5,del_index) == "DEL" ) {
	          // send a standard http response header
	          client.println("HTTP/1.1 200 OK");
	          client.println("Content-Type: text/html");
	          client.println();

	          // output the value of each analog input pin
	          Serial.println("DEL");
	            client.print("Delede user: ");
	            client.println(command.substring(del_index,end_index));

//	        for (int i=0 ; i <= DB.name_count ; i++){
//	        	char c[DB.name_files[i].length()];
//	        	DB.name_files[i].toCharArray(c,DB.name_files[i].length()+1);
//	        	client.print("<li>");
//	        	client.print(c);
//	        	client.println("    del </li>");
//	        	Serial.println(DB.name_files[i]);
//	        }
	        client.println();
	        Serial.println("END ....");
//	            for (int i = 0; i<=DB.name_count; i++){
//	            	 client.println(DB.name_files[i]);
//	            	 Serial.println(DB.name_files[i]);
//	            }

//	             client.print(DB.list_files());
	        break;
	        }

		     if ( c == '\n' ) {
	            // everything else is a 404
	            client.println("HTTP/1.1 404 Not Found");
	            client.println("Content-Type: text/html");
	            client.println();
	            client.println("<h2>File Not Found!!!</h2>");
	            break;
	        }
	      }
	    }
	    // give the web browser time to receive the data
	    delay(1);
	    // close the connection:
	    client.stop();
	  }
	  delay(500);
	  Serial.print(".");
//    // ����� ����� ���������� � 1-��� ��������
//    // �������� ��� ����� �� ������� ����� ������
//    byte someByte = buf[2];
//    Serial.println(buf[2], HEX);
//    // � ������������ � ����������� ������ - ����� ����������
//    // ������� ����� ��� �� ����� (4 ������, ����� �����, ������) youtu.be/e0huL_LpFj4
////    if(someByte==0x95) blinkLed(ledRed,2);
////    else if(someByte==0x72) blinkLed(ledGreen,3);
////    else if(someByte==0x86) blinkLed(ledBlue,4);
////    else if(someByte==0x03) blinkLed(ledRed,1);
////    else if(someByte==0x06) blinkLed(ledRed,5);
////    else if(someByte==0x78) blinkLed(ledGreen,6);
////    else if(someByte==0x10) blinkLed(ledBlue,7);
//  }
}

